﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

namespace Awesom_O_Controller
{
    public class DiabloWatcher
    {
        int _loginAttempts;
        bool _allowEvents, _firstJoin;
        public bool Running;

        AwesomoControllerClient _controllerClient;
        DiabloHandler _diabloHandler;
        Process _diabloProcess = new Process();
        readonly Stopwatch _gameLengthTimer = new Stopwatch();
        public Profile Profile;

        public DiabloWatcher(Profile profile)
        {
            Profile = profile;
        }

        #region Diablo Watcher External Commands

        public void Start()
        {
            _firstJoin = true;
            _loginAttempts = 0;
            Extras.SetRealm();
            Running = true;            
            new Thread(ConnectController).Start();
        }

        public void Stop()
        {
            _allowEvents = false;
            Running = false;
            _controllerClient.Stop();
            CloseDiablo();
        }

        public void Restart()
        {
            _allowEvents = false;
            Running = false;
            _controllerClient.Stop();
            CloseDiablo();

            _firstJoin = true;
            _loginAttempts = 0;
            Extras.SetRealm();
            Running = true;
            new Thread(ConnectController).Start();
        }

        #endregion

        #region Diablo Watcher Internal Commands

        private void ConnectController()
        {
            _controllerClient = new AwesomoControllerClient("127.0.0.1");
            _controllerClient.PacketReceived += ControllerPacketReceived;

            if (_controllerClient.IsClientConnected) return;
            Log.Info("Connecting to Awesom-O Core", Profile.Name);

            var stopWatch = new Stopwatch();
            stopWatch.Start();

            while (true)
            {
                _controllerClient.CreateNewControllerClient(Profile.DiabloOwnerName);
                Thread.Sleep(500);
                if (_controllerClient.IsClientConnected)
                {
                    Log.Info("Connected to Awesom-O Core", Profile.Name);
                    break;
                }
                if ((stopWatch.ElapsedMilliseconds/1000) < 20) continue;
                Log.Error("Error Connecting to Awesom-O Core", Profile.Name);
                return;
            }
            /*if (!string.IsNullOrEmpty(CurrentClassicKey) && (!string.IsNullOrEmpty(CurrentExpKey)))
                {
                    Log.Info("Keys are empty, adding getting next set!");
                    Thread.Sleep(500);
                    Log.Info("Going to send key to controller");
                    ControllerClient.AddCdkey(CurrentClassicKey, "6");
                    Thread.Sleep(500);
                    ControllerClient.AddCdkey(CurrentExpKey, "10");
                    Log.Info("Added Cdkeys to Core!");
                    Thread.Sleep(1000);
                }*/
            _controllerClient.Start();
        }

        private void AdjustDefaultUsername()
        {
            RegistryKey blizzardSoftwareKey = Registry.CurrentUser.OpenSubKey("Software\\Blizzard Entertainment\\Diablo II", true);
            if (blizzardSoftwareKey == null) return;
            var data = Profile.BnetAccount;
            blizzardSoftwareKey.SetValue("Last BNet", data);
        }

        private void StartDiablo()
        {
            _diabloProcess = D2Multi.StartD2Multi(Profile.DiabloPath, Profile.Name);
            _allowEvents = true;
            new Thread(ErrorWatcher).Start();
        }

        private void CloseDiablo()
        {
            if (_diabloProcess != null)
            {
                try
                {
                    _diabloProcess.CloseMainWindow();
                    Thread.Sleep(100);
                }
                catch { }
            }
        }

        private void DiabloWindowHandlerAdjust()
        {
            _diabloProcess = Extras.FindDiabloByName(Profile.Name);
            _diabloHandler = new DiabloHandler(_diabloProcess.MainWindowHandle);
            Login();
        }

        private void TempIpBanned()
        {
            Stop();
            Thread.Sleep(60000);
            Start();
        }

        #endregion

        #region DiabloHandler Commands

        private void Login()
        {
            _diabloHandler.Login(Profile.BnetPassword);
        }

        private void SelectCharacter()
        {
            _diabloHandler.SelectChar(Profile.BnetCharacterPosition);
        }

        private void MakeGame()
        {
            if (!_firstJoin)
            {
                int gameTime = Convert.ToInt32(_gameLengthTimer.ElapsedMilliseconds / 1000);
                if (gameTime < 180)
                {
                    Log.Info("Waiting " + (180 - gameTime) + " seconds in lobby.");
                    Thread.Sleep((180 - gameTime) * 1000);
                }
            }
            else
                _firstJoin = false;

            Thread.Sleep(3000);
            _diabloHandler.CreateGame(_diabloHandler.RandomString(_diabloHandler.RandomNumber(6, 10)), _diabloHandler.RandomString(_diabloHandler.RandomNumber(4, 8)), Profile.BnetDifficulty);
        }

        #endregion

        #region Error Handling

        private void ErrorWatcher()
        {
            while (_allowEvents)
            {
                try
                {
                    if (!_diabloProcess.HasExited && !_diabloProcess.Responding)
                    {
                        Thread.Sleep(5000);
                        if (!_diabloProcess.HasExited && !_diabloProcess.Responding)
                        {
                            Restart();
                            break;
                        }
                    }
                    else if (_diabloProcess.HasExited)
                    {
                        Log.Error("Diablo II has exited", Profile.Name);
                        Restart();
                        break;
                    }
                    else if (!Extras.DiabloWindowExistsByName(Profile.Name))
                    {
                        Log.Error("Diablo II has exited", Profile.Name);
                        Restart();
                        break;
                    }
                    /*else if (true)
                        Log.Debug(_diabloProcess.MainWindowHandle.ToString(), Profile.Name);
                    /*else if (GameLengthTimer.IsRunning && Location == Awesom_O_Controller.Location.Ingame)
                    {
                        if ((GameLengthTimer.ElapsedMilliseconds / 1000) >= MaxGameTime)
                        {
                            Location = Awesom_O_Controller.Location.None;
                            Intervention(this, new GlobalEventArgs(GlobalEventArgs.EventCode.MaxGameTimeExpired, true));
                            GameLengthTimer.Reset();
                        }
                        else
                        {
                            UpdateStatus("In-Game (" + (GameLengthTimer.ElapsedMilliseconds / 1000) + "s)");
                        }
                    }*/
                    else if (_diabloProcess.MainWindowTitle.Contains("End Program - Diablo II"))
                    {
                        Restart();
                        break;
                    }
                    else if (_diabloProcess.MainWindowTitle.Contains("Diablo II Exception"))
                    {
                        Restart();
                        break;
                    }
                    else if (_diabloProcess.MainWindowTitle.Contains("Hey guys"))
                    {
                        Restart();
                        break;
                    }
                    else if (_diabloProcess.MainWindowTitle.Contains("Diablo II Error"))
                    {
                        Restart();
                        break;
                    }
                    else if (_diabloProcess.MainWindowTitle.Contains("Diablo II Critical Error"))
                    {
                        Restart();
                        break;
                    }
                    else if (_diabloProcess.MainWindowTitle.Contains("Game"))
                    {
                        Restart();
                        break;
                    }
                    else if (_diabloProcess.MainWindowTitle.Contains("Diablo II.exe - Application Error"))
                    {
                        Restart();
                        break;
                    }
                }
                catch { }
                Thread.Sleep(1000);
            }
        }

        #endregion

        void ControllerPacketReceived(object sender, PacketArgs myArgs)
        {
            switch (myArgs.Event)
            {
                case AwesomoControllerClient.ControllerEventPackets.ConnectionSuccessful:
                    Extras.PreventAct5Bug(Profile.DiabloPath + "\\");
                    AdjustDefaultUsername();
                    StartDiablo();
                    break;
                case AwesomoControllerClient.ControllerEventPackets.AlreadyConnected:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.BnetAuthResponse:
                    DiabloWindowHandlerAdjust();
                    break;
                case AwesomoControllerClient.ControllerEventPackets.BnetLogonResponse:
                    if (myArgs.Result == 1 && _loginAttempts <= 3 || myArgs.Result == 2 && _loginAttempts <= 3)
                    {
                        _diabloHandler.RemoveLoginError();
                        Login();
                    }
                    if (myArgs.Result == 0)
                    {
                        _loginAttempts = 0;
                        Log.Info("Login successful", Profile.Name);
                    }
                    else
                    {
                        Log.Error("Could not login", Profile.Name);
                        Stop();
                    }
                    break;
                case AwesomoControllerClient.ControllerEventPackets.CantConnect:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.TemporaryIpBan:
                    TempIpBanned();
                    break;
                case AwesomoControllerClient.ControllerEventPackets.CharacterSelect:
                    SelectCharacter();
                    break;
                case AwesomoControllerClient.ControllerEventPackets.LogonSuccess:
                    _gameLengthTimer.Stop();
                    MakeGame();
                    break;
                case AwesomoControllerClient.ControllerEventPackets.JoinChannel:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.JoinGameSuccessful:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.FailedToJoin:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.GameAlreadyExists:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.GameDoesNotExists:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.ConnectedGameProxy:
                    _gameLengthTimer.Start();
                    Thread.Sleep(2000);
                    _controllerClient.StartRun();
                    break;
                case AwesomoControllerClient.ControllerEventPackets.ExitGame:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.ItemMessage:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.StatusMessage:
                    Log.Info(myArgs.Message);
                    break;
                case AwesomoControllerClient.ControllerEventPackets.ChickenExit:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.Death:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.SocketError:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.HotIp:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.DiaClone:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.ChatEvent:
                    // Your friend %ACCOUNT% entered a Diablo II Lord of Destruction game called %GAMENAME%.
                    // myArgs.Account + myArgs.CharName + myArgs.Message
                    break;
                case AwesomoControllerClient.ControllerEventPackets.GameExp:
                    break;
                case AwesomoControllerClient.ControllerEventPackets.SetControllerVariable:
                    MessageBox.Show(myArgs.Message.Trim());
                    break;
            }
        }
    }
}
